#include "LeGraphicsRulerBar.h"
#include "LeGraphicsRuler.h"

#include <QPainter>
#include <QPaintEvent>
#include <QFontMetrics>
#include <QDebug>

// https://kernelcoder.wordpress.com/2010/08/25/how-to-insert-ruler-scale-type-widget-into-a-qabstractscrollarea-type-widget/
// http://stackoverflow.com/questions/10027008/separate-layers-like-feature-on-qgraphicsview

// FIXME: Get rid of these magic numbers and calculate them dynamically based
// on widget height or width and remove sizeHint() overload
const int LeGraphicsRulerBar::BREADTH = 23;
const int LeGraphicsRulerBar::FONT_SIZE = 10;
const int LeGraphicsRulerBar::MAJOR_TICK_HEIGHT = 6;
const int LeGraphicsRulerBar::MINOR_TICK_HEIGHT = 3;

LeGraphicsRulerBar::LeGraphicsRulerBar(LeGraphicsRulerBar::Alignment alignment, QWidget *parent) :
    QWidget(parent),
    m_ruler(nullptr),
    m_alignment(alignment),
    m_currentPos(0)
{
}

LeGraphicsRulerBar::~LeGraphicsRulerBar()
{

}

void LeGraphicsRulerBar::setCursorPosition(const QPointF &pos)
{
    if (m_alignment == Horizontal)
    {
        m_currentPos = pos.x();
    }
    else
    {
        m_currentPos = pos.y();
    }
    update();
}

QSize LeGraphicsRulerBar::minimumSizeHint() const
{
    if (m_alignment == Horizontal)
    {
        return QSize(m_ruler->size(), BREADTH);
    }
    else
    {
        return QSize(BREADTH, m_ruler->size());
    }
}

LeGraphicsRulerBar::Alignment LeGraphicsRulerBar::rulerType() const
{
    return m_alignment;
}

void LeGraphicsRulerBar::setRuler(const LeGraphicsRuler *ruler)
{
    if (m_ruler != nullptr)
        m_ruler->disconnect(this);

    m_ruler = ruler;

    if (m_ruler != nullptr)
    {
        connect(m_ruler, &LeGraphicsRuler::changed,
                this, [this]() {
            update();
            updateGeometry();
        });
    }

    update();
    updateGeometry();
}

const LeGraphicsRuler *LeGraphicsRulerBar::ruler() const
{
    return m_ruler;
}

void LeGraphicsRulerBar::setBackgroundColor(const QColor &color)
{
    if (m_backgroundColor == color)
    {
        return;
    }
    m_backgroundColor = color;
    update();
}

QColor LeGraphicsRulerBar::backgroundColor() const
{
    return m_backgroundColor;
}

void LeGraphicsRulerBar::setForegroundColor(const QColor &color)
{
    if (m_foregroundColor == color)
    {
        return;
    }
    m_foregroundColor = color;
    update();
}

QColor LeGraphicsRulerBar::foregroundColor() const
{
    return m_foregroundColor;
}

void LeGraphicsRulerBar::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    if (m_ruler == nullptr)
    {
        return;
    }

    QPainter painter(this);
    painter.setClipRect(event->rect());
    painter.fillRect(event->rect(), m_backgroundColor);

    QPen pen(m_foregroundColor, 0);
    QBrush brush(m_foregroundColor);
    painter.setPen(pen);
    painter.setBrush(brush);

    auto values = m_ruler->majorValues();
    auto ticks = m_ruler->majorTicks();
    for (int i = 0; i < ticks.count(); i++)
    {
        drawMajorTick(painter, ticks[i], values[i]);
    }

    ticks = m_ruler->minorTicks();
    for (int i = 0; i < ticks.count(); i++)
    {
        drawMinorTick(painter, ticks[i]);
    }

    drawIndicator(painter, m_ruler->tickPosition(m_currentPos));
}

void LeGraphicsRulerBar::drawMajorTick(QPainter &painter, int pixelPos, qreal logicalPos)
{
    QFont font = painter.font();
    font.setPixelSize(FONT_SIZE);
    painter.setFont(font);
    QString text = QString("%1").arg(logicalPos);
    QFontMetrics fontMetrics(font);
    int textWidth = fontMetrics.width(text);
    if (m_alignment == Horizontal)
    {
        painter.drawText(QPointF(pixelPos - textWidth / 2, FONT_SIZE + 2), text);
        painter.drawLine(QPointF(pixelPos, (BREADTH - 1) - MAJOR_TICK_HEIGHT),
                         QPointF(pixelPos, (BREADTH - 1)));
    }
    else
    {
        painter.save();
        painter.translate(FONT_SIZE + 2, pixelPos + textWidth / 2);
        painter.rotate(-90);
        painter.drawText(0, 0, text);
        painter.restore();
        painter.drawLine(QPointF((BREADTH - 1) - MAJOR_TICK_HEIGHT, pixelPos),
                         QPointF((BREADTH - 1),                     pixelPos));
    }
}

void LeGraphicsRulerBar::drawMinorTick(QPainter &painter, int pixelPos)
{
    if (m_alignment == Horizontal)
    {
        painter.drawLine(QPointF(pixelPos, (BREADTH - 1) - MINOR_TICK_HEIGHT),
                         QPointF(pixelPos, (BREADTH - 1)));
    }
    else
    {
        painter.drawLine(QPointF((BREADTH - 1) - MINOR_TICK_HEIGHT, pixelPos),
                         QPointF((BREADTH - 1),                     pixelPos));
    }
}

void LeGraphicsRulerBar::drawIndicator(QPainter &painter, int pixelPos)
{
    static const int cursorWidth = 6;
    static const int cursorHeight = 3;

    QPolygon shape;
    if (m_alignment == Horizontal)
    {
        shape << QPoint(-(cursorWidth >> 1), 0)
              << QPoint(+(cursorWidth >> 1), 0)
              << QPoint(0,                 cursorHeight - 1);
        shape.translate(pixelPos, (BREADTH - 1) - MAJOR_TICK_HEIGHT + 1);
    }
    else
    {
        shape << QPoint(0,              +(cursorWidth >> 1))
              << QPoint(0,              -(cursorWidth >> 1))
              << QPoint(cursorHeight - 1, 0);
        shape.translate((BREADTH - 1) - MAJOR_TICK_HEIGHT + 1, pixelPos);
    }
    painter.drawPolygon(shape);
}
